
import json
from datetime import datetime
from django import http
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.paginator import Paginator
from django.db import transaction
from django.shortcuts import render
from django.views import View

from goods.models import SKU
from meiduo_mall.utils.response_code import RETCODE
from orders.models import OrderInfo, OrderGoods
from users.models import Address
from django_redis import get_redis_connection
#点击我的购物车取结算的时候，渲染出模板页面，通过的是a标签超链接
class SettlementView(LoginRequiredMixin,View):#在没有登陆的情况下，点击结算会返回到首页
    def get(self,request):
        user = request.user
        #查询收货地址
        addresses = Address.objects.filter(user_id =user.id,is_delete=False)#user_id 当前用户ｉｄ--表user.id
        default_address_id = user.default_address_id
        #查询购物车中选中的商品
        redis_cli = get_redis_connection('carts')
        #从hash中查询数据
        cart_dict = redis_cli.hgetall('cart%d'%user.id)
        cart_dict = {int(sku_id):int(count) for sku_id ,count in cart_dict.items()}
        #从set中查询已经选中的商品
        selected_list = redis_cli.smembers('selected%d'%user.id)
        selected_list = [int(sku_id) for sku_id in  selected_list]
        #查询所有选中的商品
        skus = SKU.objects.filter(pk__in =selected_list,is_launched=True)
        sku_list = []
        total_count =0
        total_money = 0
        freight = 10 #运费
        for sku in skus:
            #总数量
            total_count +=cart_dict[sku.id]#注意这块当前商品的编号，对应字典的数量
            #每一种商品的总钱数，小计，一下遍历得到的是商品信息
            total_amount = sku.price*cart_dict[sku.id]
            #总钱数
            total_money += total_amount
            sku_list.append({
                'id':sku.id,
                'name':sku.name,
                'default_image_url':sku.default_image.url,
                'price':sku.price,
                'count':cart_dict[sku.id],
                'total_amount':total_amount


            })

        pay_money = freight +total_money

        context = {
            'addresses':addresses,
            'default_address_id':default_address_id,
            'pay_money':pay_money,
            'sku_list':sku_list,
            'freight':freight,
            'total_count':total_count,
            'total_money':total_money



        }
        return  render(request,'place_order.html',context)
#购物车结算

#1,查询收货地址，显示默认地址
# ２,链接reids 查询购物车商品ｉｄ　，和选中状态集合，转化字节类型，
# ３,查询sku　过滤选中商品,允许结算，遍历查询到的商品，拿出商品的数据，根据前端页面需要的数据，
#4每种商品的小计，每种商品的数量，运费，每类商品的总价格，
#总数量，总钱数，总支付钱数包含运费　

# -----------------------------------------------------
#点击提交订单，发送ajax　－post请求　进入
class OrderCommitView(LoginRequiredMixin,View):
    def post(self,request):
        user = request.user
        #接受
        param_dict = json.loads(request.body.decode())
        address_id = param_dict.get('address_id')
        pay_method = param_dict.get('pay_method')

        #验证参数，非空
        if not all([address_id,pay_method]):
            return http.JsonResponse({'code':RETCODE.PARAMERR,'errmsg':'参数不齐'})
        #判断收货地址的有效性
        try:
            address = Address.objects.get(pk = address_id,user_id = user.id) #address关联的是user这个表格
        except:
            return  http.JsonResponse({'code':RETCODE.PARAMERR,'errmsg':'地址的信息无效'})

        #判断支付方式有两种１，代表货到付款，２表示支付宝支付，
        if pay_method not in [1,2]:
            return http.JsonResponse({'code':RETCODE.PARAMERR,'errmsg':'支付的方式无效'})
        #从购物车中查询商品信息，１，链接redis hash set　　建立相同的输出方式
        redis_cli = get_redis_connection('carts')
        #从hash 中得到字典，bytes转移
        cart_dict = redis_cli.hgetall('cart%d'%user.id)
        if not cart_dict :#判断一个列表，集合有没有数据用not
            return  http.JsonResponse({'code':RETCODE.PARAMERR,'errmsg':'宝贝,你购物车的商品为空,请返回首页购买后再提交'})
        cart_dict = {int(sku_id):int(count) for sku_id,count in cart_dict.items()}
        #从set中获取被选中的商品id
        selecteds = redis_cli.smembers('selected%d'%user.id)
        if not selecteds :
            return http.JsonResponse({'code': RETCODE.PARAMERR, 'errmsg': '小姐姐,你还没有选中购买的商品，请返回购物车选中'})
        selected_list =[int(sku_id) for sku_id in selecteds]
        # 在与数据库建立交互的接口处创建事物,这个包是django　db自带的事物
        with transaction.atomic():
                # 开启事物,创建一个开始节点,将下面的代码全部都放在事物中
            sid = transaction.savepoint()
            #创建订单对象
            now = datetime.now()#表示在创建该订单时的当前时间
            total_count = 0
            total_amount =0 #表示小计，该类商品的价格总计
            if pay_method == 1:
                status =2
            else:
                status =1
            order_id = '%s%09d'%(now.strftime('%Y%m%d%H%M%S'),user.id)

            #将该表的字段传入
            order = OrderInfo.objects.create(
                order_id=order_id,
                user_id=user.id,
                address_id=address_id,
                total_count=total_count,
                total_amount=total_amount,
                freight=10,
                pay_method=pay_method,
                status=status
            )
            # 3.查询库存商品，遍历
            skus = SKU.objects.filter(pk__in=selected_list, is_launched=True)
            for sku in skus:
                count = cart_dict[sku.id]
                # 判断库存是否足够，如果不足则返回提示，如果库存足够，则继续
                if sku.stock < count:
                    # 当条件出现错误回滚事物到起始节点，保证程序的一致性
                    transaction.savepoint_rollback(sid)
                    return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库存不足'})
                # 当多个用户购买发生资源竞争，线程得到的时间片，在没有保存在数据库就暂停，而下一个用户正好拿到此商品，出现数据库数据错乱
                #time.sleep(12)
                # 修改商品的库存、销量
                # sku.stock -= count
                # sku.sales += count
                # sku.save()
                #这里调用乐观锁防止高并发出现资源竞争，数据错乱
                stock_old = sku.stock #检查库存量是否发生变化
                stock_new = stock_old - count
                sales_new = sku.sales + count
                #合并成sql一条执行语句，在查询判断是否为原来库存量，是则修改属性，不是result　= 0
                result = SKU.objects.filter(pk = sku.id, stock = stock_old).update(stock = stock_new,sales = sales_new)
                if result == 0:
                    #回滚事物
                    transaction.savepoint_rollback(sid)
                    return http.JsonResponse({'code':RETCODE.PARAMERR,'errmsg':'亲,服务器繁忙，请稍后重试'})
                # 创建订单商品对象
                order_goods = OrderGoods.objects.create(
                    order_id=order_id,
                    sku_id=sku.id,
                    count=count,
                    price=sku.price
                )
                # 计算总数量、总金额
                total_count += count
                total_amount += count * sku.price
            # 4.修改订单对象的总金额、总数量
            order.total_count = total_count
            order.total_amount = total_amount
            order.save()
            #提交事物--从保存节点到提交事物的所有数据库的操作

            transaction.savepoint_commit(sid)

            # 5.删除购物车中选中的商品
            redis_cli.hdel('cart%d' % user.id, *selected_list)
            redis_cli.delete('selected%d' % user.id)

            return http.JsonResponse({
                'code': RETCODE.OK,
                'errmsg': 'ok',
                'order_id': order_id,

            })
    #提交订单的逻辑，当点击提交订单时发送ajax post 请求，设计到提交订单后需要和数据库进行交互，保存，当多个用户在统一时刻，
    #进行高并发操作时，由于线程分布的时间片时间有限，出现数据错杂，---事物，乐观锁---提交订单就是在和数据库进行交互
#-----------------------------------------------------------------------
##当点击提交订单的时候触发点击事件，发送ajax get 请求的方式渲染支付成功的页面页面---这个页面显示有个去支付的点击按钮，链接支付宝

class SuccessView(View):
    def get(self,request):
        user =request.user
        #接受
        order_id = request.GET.get('order_id')
        payment_amount = request.GET.get('payment_amount')
        pay_method = int(request.GET.get('pay_method'))
        #ajax　get得到的数据类型都是字符串，改变数据原来的类型
        #验证参数，非空
        if not all([ order_id,payment_amount,pay_method]):
            return http.JsonResponse({'code':RETCODE.PARAMERR,'errmsg':'参数不齐'})
        if pay_method not in [1, 2]:
            return http.JsonResponse({'code': RETCODE.PARAMERR, 'errmsg': '支付的方式无效'})
        #处理
        context ={
            'order_id':order_id,
            'payment_amount':payment_amount,#实际在渲染页面的时候已经查询出来pay_money,在前端页面做个变量赋值给js
            'pay_method':pay_method

        }

        # 响应
        return render(request,'order_success.html',context)
# -----------------------------------------------------------------------------

class OrderListView(LoginRequiredMixin, View):
    def get(self, request, page_num):
        # 查询当前用户的所有订单
        order_list = OrderInfo.objects.filter(user_id=request.user.id).order_by('-create_time')

        # 分页
        paginator = Paginator(order_list, 4)
        page = paginator.page(page_num)

        # 转换成前端需要的格式
        page_list = []
        for order in page:
            detail_list = []
            for detail in order.skus.all():
                detail_list.append({
                    'default_image_url': detail.sku.default_image.url,
                    'name': detail.sku.name,
                    'price': detail.price,
                    'count': detail.count,
                    'total': detail.price * detail.count
                })

            page_list.append({
                'create_time': order.create_time,
                'order_id': order.order_id,
                'detail_list': detail_list,
                'total_amount': order.total_amount,
                'freight': order.freight,
                'status': order.status,
            })

        context = {
            'page': page_list,
            'page_num': page_num,
            'page_total': paginator.num_pages
        }

        return render(request, 'user_center_order.html', context)
#
# 订单页面的逻辑：
# 需要在我的订单里面显示详情，首先查询当前用户的所有订单，时间的先后排序，，调用分页类，
# paginator  = paginator(order_list,2)
# page  = paginator.page(page_num)
# for i in page:
# ----------------------------------------------------------------
# 去评价

# 点击去评价，会触发a标签的超链接，到vue，将路径回调到地址栏，浏览器请求
class CommentView(LoginRequiredMixin,View):
    def get(self,request):
        #接受
        order_id = request.GET.get('order_id')
        #验证
        try:

            order = OrderInfo.objects.get(pk = order_id)
        except:
            return render(request,'404.html')
        #查询当前订单中的没有被评论的商品
        skus_comment = order.skus.filter(is_commented =False)
        sku_list = []
        for sku_notcomment in skus_comment:
            sku_list.append({
                'order_id':order_id,
                'default_image_url':sku_notcomment.sku.default_image.url,
                'name':sku_notcomment.sku.name,
                'price':str(sku_notcomment.sku.price),
                'sku_id':sku_notcomment.sku_id


            })

        context = {

            'skus':sku_list
        }


        return render(request,'goods_judge.html',context)
#点击提交发送一个ajax请求
    def post(self,request):
        parm_dict = json.loads(request.body.decode())
        order_id = parm_dict.get('order_id')
        sku_id = parm_dict.get('sku_id')
        comment = parm_dict.get('comment')
        score = parm_dict.get('score')
        is_anonymous = parm_dict.get('is_anonymous',False) #是否匿名

        #判断非空
        if not all([order_id,sku_id,comment,score]):
            return http.JsonResponse({'code':RETCODE.PARAMERR,'errmsg':'参数不齐'})
        #检查当前用户订单商品是否存在
        try:
            order_goods = OrderGoods.objects.get(sku_id = sku_id,order_id = order_id)
        except:
            return  http.JsonResponse({'code':RETCODE.PARAMERR,'errmsg':'不存在此订单的商品'})
        #这些数据没有数据，将修改订单商品保存到数据库,在提交订单时一部分数据实际已经保存在数据中
        order_goods.comment = comment
        order_goods.score = score
        order_goods.is_anonymous = is_anonymous
        order_goods.is_commented = True
        order_goods.save()
        #修改订单状态，一个订单包含多个商品，一个订单所有商品都评论后，修改订单状态
        order = order_goods.order#修改当前订单状态
        if order.skus.filter(is_commented = False).count()<= 0:#一个订单的所有商品都已经被评论
            order.status = 5
            order.save()
        return http.JsonResponse({'code':RETCODE.OK,'errmsg':'ok'})
# 订单评论逻辑思维,首先接受到模板渲染后的页面，当点击提交评论的时候发送ajax 请求，得到请求数据，解析数据查询
# 当前订单用户的所有商品，创建一个商品对象，修改当前商品对象的订单商品的部分属性,保存，当查询当前订单所有商品评论完成后修改订单状态
#


class CommentListView(View):
    def get(self, request, sku_id):
        comments = OrderGoods.objects.filter(sku_id=sku_id, is_commented=True).order_by('-create_time')
        comment_list = []
        for comment in comments:
            comment_list.append({
                'username': '****' if comment.is_anonymous else comment.order.user.username,
                'score': comment.score,
                'comment': comment.comment
            })
        return http.JsonResponse({
            'code': RETCODE.OK,
            'errmsg': '',
            'goods_comment_list': comment_list
        })
